import os
from datetime import datetime
from shutil import rmtree


class UPath:
    @staticmethod
    def path_join(*_path, formatter: str = ""):
        """
        替代os.path.join
        :param _path:
        :param formatter 路径格式，默认为空，根据操作系统自适应，如果指定linux或windows， 则按照指定的操作系统路径格式执行
        :return:
        """
        if formatter.lower() == "windows":
            sep = "\\"
        elif formatter.lower() == "linux":
            sep = "/"
        else:
            return os.path.join(*_path)

        return_path = ""
        for s_path in _path:
            if s_path:
                return_path = return_path + s_path + sep
        return return_path[:-1]

    @staticmethod
    def get_path_seperator():
        """

        :return '/' or '\' according OS

        """
        if os.name == "nt":
            return "\\"
        else:
            return "/"

    @staticmethod
    def make_dir(dir_path: str, remake: bool = False):
        """
        make a dir, if dir is existing, return directly, elif path exists, but it is not a dir, raise error
        else, name as dir_name
        Args:
            dir_path:
            remake:

        Returns:
        """
        if os.path.exists(dir_path) and remake:
            rmtree(dir_path)
        if os.path.exists(dir_path) and not os.path.isdir(dir_path):
            raise FileExistsError(f"目录路径{dir_path}存在且不是文件夹！！")
        os.makedirs(dir_path, exist_ok=True)

    @classmethod
    def make_sub_dir(cls, father_path: str, sub_dir_name: str, remake: bool = False):
        """
        make a sub dir name as sub_dir_name under father_path
        Args:
            father_path:
            sub_dir_name:
            remake

        Returns:
            sub dir full path string, ending with '/' or '\' according OS

        """
        full_path = os.path.join(father_path, sub_dir_name)
        cls.make_dir(full_path, remake)
        return full_path

    @classmethod
    def u_copy(cls, src_path: str, dst_dir: str, exist_ok=True):
        """
        make a sub dir name as sub_dir_name under father_path
        Args:
            src_path:
            dst_dir:
            exist_ok:

        Returns:
            sub dir full path string, ending with '/' or '\' according OS

        """
        if not os.path.exists(src_path) or not os.path.exists(dst_dir):
            raise FileNotFoundError("源/目的文件/目录不存在")

        dst_path = os.path.join(dst_dir, os.path.basename(src_path))

        if os.path.exists(dst_path):
            if exist_ok:
                rmtree(dst_path)
            else:
                raise FileExistsError("目的文件/目录已存在")

        if os.name == "posix":
            cmd = f"cp {src_path} {dst_dir}"
        elif os.name == "nt":
            cmd = f"copy {src_path} {dst_dir}"
        else:
            raise SyntaxError("Not support system")

        os.system(cmd)

    @staticmethod
    def remove(_path: str):
        """
        Delete specific dir
        :param _path: file or dir path
        :return: None
        """
        if not os.path.exists(_path):
            return
        if os.path.isdir(_path):
            rmtree(_path)
        else:
            os.remove(_path)

    @staticmethod
    def base_name(_object: str):
        """
        获取对象的文件名/路径名，对象可以是文件，也可以是文件夹
        :param _object:
        :return:
        """
        return os.path.basename(_object)

    @staticmethod
    def dir_name(_object: str):
        """
        获取对象所在文件夹的绝对路径，对象可以是文件，也可以是文件夹
        :param _object:
        :return:
        """
        return os.path.dirname(_object)

    @staticmethod
    def abspath(_object: str):
        """
        获取对象的绝对路径
        :param _object:
        :return:
        """
        return os.path.abspath(_object)

    @staticmethod
    def file_walk(_path, pattern: str = None):
        """
        基于os.walk的封装，增加了后缀过滤的功能
        :param pattern: 匹配文件名
        :param _path:
        :return:
        """
        for root, dirs, files in os.walk(_path):
            if pattern:
                new_files = list()
                for file in files:
                    if file.endswith(pattern):
                        new_files.append(file)
                if files:
                    yield root, dirs, new_files
            else:
                yield root, dirs, files

    @staticmethod
    def file_traverse(_path, pattern: str = None):
        """
        文件遍历，输出文件绝对路径的迭代
        :param pattern: 匹配文件名
        :param _path:
        :return:
        """
        for root, dirs, files in os.walk(_path):
            if pattern:
                new_files = list()
                for file in files:
                    if file.endswith(pattern):
                        new_files.append(file)
                files = new_files

            for _file in files:
                relative_path = os.path.join(root, _file)
                yield relative_path

    @staticmethod
    def is_son_exist(father_path: str, son_name: str, exist_error: bool = True):
        """
        check if a dir/file name as sub_dir_or_file_name exists in father_path, if not, raise error
        Args:
            father_path:
            son_name:
            exist_error

        Returns:
            sub dir full path string, ending with '/' or '\' according OS

        """
        full_path = os.path.join(father_path, son_name)
        if os.path.exists(full_path):
            return True
        if exist_error:
            raise FileNotFoundError(f"[Path_Error 2] No such file or directory: '{son_name}' in {father_path}")
        return False

    @staticmethod
    def path_exists(_path):
        """
        替代os.path.exists
        :param _path:
        :return:
        """
        return os.path.exists(_path)

    @staticmethod
    def is_dir(_path):
        """
        替代os.path.isdir
        :param _path:
        :return:
        """
        return os.path.isdir(_path)

    @staticmethod
    def get_file_modify_time(file_path, res_type:str = "float"):
        try:
            update_time = os.path.getmtime(file_path)
            if res_type == "float":
                return update_time
            else:
                datetime_obj = datetime.fromtimestamp(update_time)
                update_time = datetime_obj.strftime("%Y-%m-%d %H:%M:%S")
                return update_time
        except OSError:
            return "File not found or error occurred"

    @classmethod
    def is_file_modified(cls, file_path: str, last_time: float):
        """
        判断自从last_time后文件是否有更新
        :param file_path:
        :param last_time:
        :return:
        """
        modify_time = cls.get_file_modify_time(file_path)
        return modify_time > last_time if isinstance(modify_time, float) else False
